﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration;
using Microsoft.Practices.Unity.InterceptionExtension;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Configuration;

namespace PolicyInjectionExtension
{
    ///// <summary>
    ///// A <see cref="ConfigurationElement"/> that maps the information about
    ///// a policy from the configuration source.
    ///// </summary>
    //public class PolicyDataExtension 
    //{
    //    private const string HandlersPropertyName = "handlers";
    //    private const string MatchingRulesPropertyName = "matchingRules";


    //    /// <summary>
    //    /// Creates a new <see cref="PolicyData"/> with the given name.
    //    /// </summary>
    //    /// <param name="policyName">Name of the policy.</param>
    //    public PolicyDataExtension(string policyName)
    //        :this()
    //    {
    //        Name = policyName;
    //    }

    //    /// <summary>
    //    /// Creates a new <see cref="PolicyData"/> with no name.
    //    /// </summary>
    //    public PolicyDataExtension() 
    //    {
    //        Handlers = new List<ICallHandler>();
    //        MatchingRules = new List<IMatchingRule>();
    //    }

    //    public string Name
    //    {
    //        get;
    //        set;
    //    }

    //    /// <summary>
    //    /// Gets or sets the collection of matching rules  
    //    /// </summary> 
    //    public List<IMatchingRule> MatchingRules
    //    {
    //        get;
    //        set;
    //    }

    //    /// <summary>
    //    /// Get or sets the collection of handlers 
    //    /// </summary> 
    //    public List<ICallHandler> Handlers
    //    {
    //        get;
    //        set;
    //    }
 
    //    internal void ConfigureContainer(IUnityContainer container )
    //    {
    //        Interception interception = container.Configure<Interception>();
    //        if (interception == null)
    //        {
    //            interception = new Interception();
    //            container.AddExtension(interception);
    //        }

    //        var policy = interception.AddPolicy(this.Name);

    //        foreach (var rule in this.MatchingRules)
    //        {
    //            policy.AddMatchingRule(rule);
    //        }

    //        foreach (var handler in this.Handlers)
    //        {
    //            policy.AddCallHandler(handler);
    //        }
             
    //        // make it a singleton - no API support for this.
    //        container.RegisterType<RuleDrivenPolicy>(this.Name, new ContainerControlledLifetimeManager());
    //    }
    //}

    /// <summary>
    /// A <see cref="ConfigurationElement"/> that maps the information about
    /// a policy from the configuration source.
    /// </summary>
    public class PolicyDataExtension : NamedConfigurationElement
    {
        private const string HandlersPropertyName = "handlers";
        private const string MatchingRulesPropertyName = "matchingRules";


        /// <summary>
        /// Creates a new <see cref="PolicyData"/> with the given name.
        /// </summary>
        /// <param name="policyName">Name of the policy.</param>
        public PolicyDataExtension(string policyName)
            : base(policyName )
        {
            Handlers = new List<ICallHandler>();
            MatchingRules = new List<IMatchingRule>();
        }

        /// <summary>
        /// Creates a new <see cref="PolicyData"/> with no name.
        /// </summary>
        public PolicyDataExtension()
            :base()
        {
            Handlers = new List<ICallHandler>();
            MatchingRules = new List<IMatchingRule>();
        }

        //public string Name
        //{
        //    get;
        //    set;
        //}

        /// <summary>
        /// Gets or sets the collection of matching rules  
        /// </summary> 
        public List<IMatchingRule> MatchingRules
        {
            get;
            set;
        }

        /// <summary>
        /// Get or sets the collection of handlers 
        /// </summary> 
        public List<ICallHandler> Handlers
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the collection of matching rules from configuration.
        /// </summary>
        /// <value>The matching rule data collection.</value>
        [ConfigurationProperty(MatchingRulesPropertyName)]
        public NameTypeConfigurationElementCollection<MatchingRuleData, CustomMatchingRuleData> ConfigureMatchingRules
        {
            get { return (NameTypeConfigurationElementCollection<MatchingRuleData, CustomMatchingRuleData>)base[MatchingRulesPropertyName]; }
            set { base[MatchingRulesPropertyName] = value; }
        }

        /// <summary>
        /// Get or sets the collection of handlers from configuration.
        /// </summary>
        /// <value>The handler data collection.</value>
        [ConfigurationProperty(HandlersPropertyName)]
        public NameTypeConfigurationElementCollection<CallHandlerData, CustomCallHandlerData> CconfigureHandlers
        {
            get { return (NameTypeConfigurationElementCollection<CallHandlerData, CustomCallHandlerData>)base[HandlersPropertyName]; }
            set { base[HandlersPropertyName] = value; }
        }

        internal void ConfigureContainer(IUnityContainer container)
        {
            Interception interception = container.Configure<Interception>();
            if (interception == null)
            {
                interception = new Interception();
                container.AddExtension(interception);
            }

            var policy = interception.AddPolicy(this.Name);

            foreach (var rule in this.MatchingRules)
            {
                policy.AddMatchingRule(rule);
            }

            foreach (var handler in this.Handlers)
            {
                policy.AddCallHandler(handler);
            }
 
            // make it a singleton - no API support for this.
            container.RegisterType<RuleDrivenPolicy>(this.Name, new ContainerControlledLifetimeManager());
        }

        internal void ConfigureContainer(IUnityContainer container, IConfigurationSource configurationSource)
        {
            Interception interception = container.Configure<Interception>();
            if (interception == null)
            {
                interception = new Interception();
                container.AddExtension(interception);
            }

            var policy = interception.AddPolicy(this.Name);

            foreach (var rule in this.ConfigureMatchingRules )
            {
                rule.ConfigurePolicy(policy, configurationSource);
            }

            foreach (var handler in this.CconfigureHandlers)
            {
                handler.ConfigurePolicy(policy, configurationSource);
            }

            // make it a singleton - no API support for this.
            container.RegisterType<RuleDrivenPolicy>(this.Name, new ContainerControlledLifetimeManager());
        }
    }
}
